Authentication
Qoyod's v2 API accepts two authentication methods. Both work on all three endpoints covered in this guide. Use whichever fits your integration architecture.
API Key Authentication
All API requests require authentication using an API key. The API key must be included in the request header.
Generating Your API Key
- Log in to your Qoyod account at https://www.qoyod.com.
- Navigate to Settings → General Settings.
- Click Generate New Key.
- Click Save to confirm.
- Important: Copy and securely store your API key immediately. For security reasons, you won't be able to view it again.
Using Your API Key
Pass your API key in a custom HTTP header on every request:
API-KEY: qyd_live_a7f3c92e1b4d8056e3a1c09f72b4d835
curl -X GET "https://api.qoyod.com/v1/accounts" \
-H "API-KEY: qyd_live_a7f3c92e1b4d8056e3a1c09f72b4d835" \
-H "Content-Type: application/json"
API key requests are never rejected for scope reasons — once the key is valid, access is granted.
OAuth Authentication
When to use OAuth: if your integration acts on behalf of a specific Qoyod user, or if your platform needs to request access without embedding a long-lived API key.
Pass the token in the standard Authorization header:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Supported Grant Flows
| Flow | Use Case |
|---|---|
| Authorization Code | Server-side web applications — recommended for most integrations |
| Client Credentials | Machine-to-machine integrations with no user context |
Available Scopes
Request only the scopes your integration needs. Qoyod's admin may restrict the scopes available to your application.
Contact your tenant admin or Qoyod support for the full list of available scopes and what resources they grant access to.
Authorization Code Flow
Use this flow when your integration acts on behalf of a Qoyod user.
Flow Overview
Step 1 — Redirect the User to Qoyod's Authorization Endpoint
Send the user's browser to:
GET https://app.qoyod.com/oauth/authorize
Required parameters:
| Parameter | Description |
|---|---|
client_id | Your application's Client ID |
redirect_uri | The URI Qoyod will redirect back to — must exactly match the one registered |
response_type | Must be code |
scope | Space-separated list of scopes (e.g., read write) |
tenant | Your organization's Qoyod tenant identifier (provided by Qoyod's admin/support) |
Example:
https://app.qoyod.com/oauth/authorize
?client_id=YOUR_CLIENT_ID
&redirect_uri=https://yourapp.com/oauth/callback
&response_type=code
&scope=read
&tenant=your-tenant-identifier
The user will be prompted to sign in (if not already) and approve the requested scopes.
Step 2 — Handle the Callback
After the user approves, Qoyod redirects to your redirect_uri with a short-lived authorization code:
https://yourapp.com/oauth/callback?code=AUTHORIZATION_CODE
If the user denies access:
https://yourapp.com/oauth/callback?error=access_denied
Important: The authorization code is single-use and expires in 10 minutes. Exchange it for an access token immediately.
Step 3 — Exchange the Code for an Access Token
POST https://app.qoyod.com/oauth/token
Content-Type: application/x-www-form-urlencoded
Request body:
| Parameter | Value |
|---|---|
grant_type | authorization_code |
code | The authorization code from Step 2 |
client_id | Your application's Client ID |
client_secret | Your application's Client Secret |
redirect_uri | Same URI used in Step 1 |
tenant | Your organization's Qoyod tenant identifier (provided by Qoyod's admin/support) |
Example (curl):
curl -X POST https://app.qoyod.com/oauth/token \
-d "grant_type=authorization_code" \
-d "code=AUTHORIZATION_CODE" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "redirect_uri=https://yourapp.com/oauth/callback" \
-d "tenant=your-tenant-identifier"
Successful response:
{
"access_token": "eyJhbGciOiJIUzUxMiJ9...",
"token_type": "Bearer",
"expires_in": 7200,
"refresh_token": "abc123...",
"scope": "read",
"created_at": 1700000000
}
Client Credentials Flow
Use this flow for server-to-server integrations that do not act on behalf of a specific user. Your application must be registered as a confidential application by your Qoyod admin.
This flow requires a confidential application. Non-confidential applications are not permitted to use client credentials. Contact your tenant admin to verify your application type.
Flow Overview
Request
POST https://app.qoyod.com/oauth/token
Content-Type: application/x-www-form-urlencoded
| Parameter | Value |
|---|---|
grant_type | client_credentials |
client_id | Your application's Client ID |
client_secret | Your application's Client Secret |
scope | Space-separated list of scopes |
tenant | Your organization's Qoyod tenant identifier (provided by Qoyod's admin/support) |
Example (curl):
curl -X POST https://app.qoyod.com/oauth/token \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "scope=read" \
-d "tenant=your-tenant-identifier"
Successful response:
{
"access_token": "eyJhbGciOiJIUzUxMiJ9...",
"token_type": "Bearer",
"expires_in": 7200,
"scope": "read",
"created_at": 1700000000
}
Using the Access Token
Include the access token as a Bearer token in the Authorization header of every API request:
GET https://app.qoyod.com/api/2.0/invoices
Authorization: Bearer YOUR_ACCESS_TOKEN
Access tokens expire after 2 hours. Check the expires_in field in the token response to know when to refresh.
Refreshing an Access Token
When an access token expires, use your refresh token to obtain a new one without requiring the user to re-authorize. Refresh tokens are issued during the Authorization Code flow.
Request
POST https://app.qoyod.com/oauth/token
Content-Type: application/x-www-form-urlencoded
| Parameter | Value |
|---|---|
grant_type | refresh_token |
refresh_token | Your current refresh token |
client_id | Your application's Client ID |
client_secret | Your application's Client Secret |
Example (curl):
curl -X POST https://app.qoyod.com/oauth/token \
-d "grant_type=refresh_token" \
-d "refresh_token=YOUR_REFRESH_TOKEN" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"
Successful response:
{
"access_token": "eyJhbGciOiJIUzUxMiJ9...",
"token_type": "Bearer",
"expires_in": 7200,
"refresh_token": "xyz789...",
"scope": "read",
"created_at": 1700003600
}
Important: Each refresh issues a new refresh token. Discard the old one and store the new one immediately.
Error Reference
| HTTP Status | Error | Meaning |
|---|---|---|
401 Unauthorized | invalid_client | Wrong client_id or client_secret |
401 Unauthorized | invalid_grant | Authorization code is expired, already used, or mismatched redirect_uri |
401 Unauthorized | Invalid refresh token | Refresh token is invalid or revoked |
401 Unauthorized | Invalid grant type | Attempted client_credentials with a non-confidential app |
403 Forbidden | Access denied | Your application is not authorized for this tenant |
401 Unauthorized | access_denied | User denied the authorization request |
Complete Integration Checklist
- Tenant admin has created an OAuth application and shared credentials with you
-
client_idandclient_secretare stored securely (not in source code or client-side assets) -
redirect_uriis registered exactly as it will be used in requests - Authorization codes are exchanged immediately upon receipt
- Access tokens are sent via
Authorization: Bearerheader over HTTPS only - Refresh tokens are stored securely and updated on every refresh
- Your application handles
401responses and triggers a token refresh or re-authorization - You have a process to contact [email protected] in case of credential compromise
Support
For integration assistance or to report a security incident (credential leakage, unauthorized access), contact:
Qoyod Support: [email protected]